package com.palm.core;

import com.palm.core.anno.Menu;
import com.palm.core.anno.Permission;
import com.palm.core.data.Item;
import com.palm.core.data.MenuItem;
import com.palm.core.util.StringUtil;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * 菜单管理
 */
public class MenuManager {

    //全部用户菜单
    private static  Map<String,MenuItem> allMenus=new ConcurrentHashMap<>();
    //全部会员菜单
    private static  Map<String,MenuItem> memberMenus=new ConcurrentHashMap<>();

    //可见控制器，有些菜单可能通过某个配置项或其他条件进行是否可见的配置
    private static Function<MenuItem,Boolean> viewSwitch = item->true;

    public static void setViewSwitch(Function<MenuItem,Boolean> sw){
        viewSwitch=sw;
    }
    public static void addMemberMenu(MenuItem item){
        _addMenu(item,memberMenus);
    }
    public static void addMenu(MenuItem item){
        _addMenu(item,allMenus);
    }

    private static void _addMenu(MenuItem item,Map<String,MenuItem> allMenus){
        if(StringUtil.isNotEmpty(item.getParent())){
            MenuItem parent=allMenus.get(item.getParent());
            if(parent==null){
                parent=new MenuItem(item.getParent(),item.getParent());
                parent.setChildren(new ArrayList<>());
                parent.getChildren().add(item);
                allMenus.put(parent.getKey(),parent);
            }else{
                if(parent.getChildren()==null){
                    parent.setChildren(new ArrayList<>());
                }
                parent.getChildren().add(item);
            }
        }
        if(allMenus.containsKey(item.getKey())){
            MenuItem old= allMenus.get(item.getKey());

            old.setIcon(item.getIcon());
            old.setOrder(item.getOrder());
            old.setParent(item.getParent());
            old.setPath(item.getPath());
            old.setTitle(item.getTitle());
        }else {
            allMenus.put(item.getKey(),item);
        }
    }

    protected  static void sortMenus(Map<String,MenuItem> allMenus){
        for(MenuItem item:allMenus.values()){
            if(item.getChildren()!=null){
                Collections.sort(item.getChildren(), Comparator.comparingInt(Item::getOrder));
            }
        }
    }
    public static void regMenu(Class c) {
        _regMenu(c,MenuManager::addMenu);
    }
    public static void regMemberMenu(Class c) {
        _regMenu(c,MenuManager::addMemberMenu);
    }
    private static void _regMenu(Class c, Consumer<MenuItem> add) {
        if (!c.isInterface()) {
            return;
        }
        String parent="";
        Menu moduleMenu= (Menu) c.getDeclaredAnnotation(Menu.class);
        if(moduleMenu==null||moduleMenu.parent().equals("\0")){
            try {
               Field f= c.getField("ID");
               parent= (String) f.get(c);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                parent=c.getName().toLowerCase().replaceFirst("menu$","");
            }
        }else{
            parent=moduleMenu.id();
        }
        if(moduleMenu!=null){
            MenuItem menuItem = new MenuItem(parent, moduleMenu.value(), moduleMenu.icon(), moduleMenu.order());
            menuItem.setPath(moduleMenu.path());
            add.accept(menuItem);
        }
        Field[] fields = c.getDeclaredFields();
        for (Field field : fields) {
            Menu menu = field.getAnnotation(Menu.class);
            String v = null;
            try {
                v = field.get(c).toString();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            if (menu != null) {
                MenuItem menuItem = new MenuItem(v, menu.value(), menu.icon(), menu.order());
                menuItem.setPath(menu.path());
                if(menu.parent().equals("\0")){
                    menuItem.setParent(parent);
                }else if(StringUtil.isEmpty(menu.parent())){
                    menuItem.setParent(null);
                }else{
                    menuItem.setParent(menu.parent());
                }
                add.accept(menuItem);
            } else {
                Permission permission = field.getAnnotation(Permission.class);
                if(permission==null){
                    continue;
                }
                MenuItem menuItem = new MenuItem(v, permission.value());
                menuItem.setOrder(permission.order());
                menuItem.setType(MenuItem.TYPE_PERMISSION);
                menuItem.setParent(permission.parent());
                add.accept(menuItem);
            }
        }
    }

    /**
     * 全部菜单权限
     * @return
     */
    public static List<MenuItem> allPermission(){
        List<MenuItem> menus=new ArrayList<>();
        allMenus.forEach((s, item) -> {
            if(item.getParent()==null){
                menus.add(item);
            }
        });
        menus.sort(Comparator.comparingInt(Item::getOrder));
        return menus;
    }
    public static Set<String> allStrPermission(){
       return allMenus.keySet();
    }
    public static List<? extends Item> getAllMemberMenu(){
//        MenuItem menuItem=memberMenus.get("-");
//        if(menuItem==null||menuItem.getChildren()==null){
//            return new ArrayList<>();
//        }
//        return menuItem.getChildren();
        return toTree(new ArrayList<>(memberMenus.values()));
    }
    public static List<MenuItem>  getAllMenu(Set<String> permissions,boolean isAdmin){
        List<MenuItem> menus=new ArrayList<>();
        allMenus.forEach((s, item) -> {
            if(item.getType()==MenuItem.TYPE_PERMISSION){
                return;
            }
            if(isAdmin){
                menus.add(new MenuItem(item));
            }else if(hasAnyPermission(permissions,item)){
                menus.add(new MenuItem(item));
            }
        });
        return toTree(menus);
    }
    private static boolean hasAnyPermission(Set<String> permissions,MenuItem menu){
        if(!viewSwitch.apply(menu)){
            return false;
        }
        if(permissions.contains(menu.getKey())){
            return true;
        }
        if(menu.getChildren()!=null){
            for(Item mi:menu.getChildren()){
                boolean h=hasAnyPermission(permissions,(MenuItem) mi);
                if(h){
                    return true;
                }
            }
        }
        return false;
    }
    private static List<MenuItem> toTree(List<MenuItem> menus){
        List<MenuItem> result=new ArrayList<>();
        Map<String,MenuItem> items=new HashMap<>();
        for(MenuItem item:menus){
            if(item.getParent()==null){
                result.add(item);
            }
            items.put(item.getKey(),item);
        }
        for(MenuItem item:menus){
            if(item.getParent()!=null){
                MenuItem parent=items.get(item.getParent());
                if(parent!=null){
                    if(parent.getChildren()==null){
                        parent.setChildren(new ArrayList<>());
                    }
                    parent.getChildren().add(item);
                }
            }
        }
        result.sort(Comparator.comparingInt(MenuItem::getOrder));
        items.forEach((s,item)->{
            if(item.getChildren()!=null){
                item.getChildren().sort(Comparator.comparingInt(Item::getOrder));
            }
        });
        return result;
    }


}
